home *** CD-ROM | disk | FTP | other *** search
-
- /*
-
- DumpSRec -- an MPW Tool
-
- Required files to build:
- DumpSRec.c
- DumpSRec.r
- DumpSRec.rsrc
- DumpSRec.make
-
- Written by Craig Prouse of Apple Developer Technical Support
- Special thanks to C.K. Haun for the original Commando interface!
- Copyright © 1990-91, Apple Computer, Inc. -- ALL RIGHTS RESERVED
-
- This tool converts an arbitrary Macintosh data file or resource into
- Motorola S-Record format, most likely to assist in downloading code
- and data to EPROM programmers or non-Macintosh target platforms.
-
- Command line syntax:
-
- DumpSRec # write resource or data in S-Record format
- DumpSRec [option…] fileName > dump ≥ progress
- -a addr # dump to hexadecimal target address (default = 0)
- -b count # include count data bytes per record (default = 32)
- -h # suppress S0 header record
- -nh # specify new data for the S0 header record
- -rt type[=id] # dump resource with this type and id (default is data fork)
- -s1 # generate S1 records, 2-byte addresses (default)
- -s2 # generate S2 records, 3-byte addresses
- -s3 # generate S3 records, 4-byte addresses
- -x addr # hexadecimal target execution address (default = 0)
-
- */
-
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <Types.h>
- #include <Traps.h>
- #include <GestaltEqu.h>
- #include <Strings.h>
- #include <QuickDraw.h>
- #include <Script.h>
- #include <Resources.h>
- #include <Dialogs.h>
- #include <Memory.h>
- #include <Files.h>
- #include <Folders.h>
- #include <Errors.h>
- #include <CursorCtl.h>
-
-
- #define kSuccess 0
- #define kSyntaxErr 1
- #define kProcErr 2
- #define kSysErr 3
- #define kUserAbort -9
- #define kBlockSize 16 * sConfig->sLineBytes /* size of buffer for FSRead */
- #define rHdrDLOG 128
- #define kHdrText 3
- #define kMaxHdrBytes 252
- #define kEqualGrayDiv 2
- #define kDlogGrayDiv 5
- #define chEnter 3
- #define chReturn 13
- #define chEscape 27
- #define sPrefsFileNameC "DumpSRec Prefs"
- #define sPrefsFileNameP "\pDumpSRec Prefs"
-
- #define topLeft(r) (((Point *) &(r))[0])
- #define botRight(r) (((Point *) &(r))[1])
- #define rectHeight(r) ((r).bottom - (r).top)
- #define rectWidth(r) ((r).right - (r).left)
-
-
- typedef short Integer; /* alias integer types to Pascal Toolbox types */
- typedef long LongInt;
- typedef enum {S0,S1,S2,S3,S7 = 7,S8,S9} TSLine;
- typedef struct {
- TSLine sLineType;
- Integer sLineBytes;
- Ptr loadAddress;
- Ptr execAddress;
- char *fileName;
- ResType resourceType;
- Integer resourceID;
- Boolean reqHeader;
- Boolean newHeader;
- } TSParms, *TPSParms;
- typedef struct {
- unsigned Integer headerAddress;
- unsigned Integer byteCount;
- unsigned char headerByte[kMaxHdrBytes];
- } TSHdrData, *TPSHdrData, **THSHdrData;
-
-
- /* global variables */
- char **argList;
- LongInt argCount;
- char **pShellVariable;
- Str255 gPrefsFile;
- FSSpec gPrefsSpecStorage, *gPrefsFileSpec = &gPrefsSpecStorage;
- Integer gDSRPrefs;
- Boolean gHasFSSpecCalls;
-
-
- /* Prototypes, in alphabetical order */
- Integer AddressSize (TSLine sType);
- void BadParmErr (void);
- void CenterWindow (WindowPtr theWindow, Rect *theRect, Boolean isDialog);
- void ChangeHeader (Handle hRsrc);
- void JamAsciiHexByte (Byte oneByte, StringPtr pStr, Integer offset);
- void MakeSLine (TSLine sType, Ptr loadAddr, Ptr pData, Integer dataBytes, StringPtr sLine);
- pascal Boolean NoDefaultButton (DialogPtr theDialog, EventRecord *theEvent, Integer *itemHit);
- Integer ParseCLParms (TSParms *usrCLParms);
- Integer SDumpBuffer (Ptr pData, LongInt count, TPSParms sConfig, Boolean termRec);
- Integer SDumpData (TPSParms sConfig);
- Integer SDumpHeader (TPSParms sConfig);
- Integer SDumpResource (TPSParms sConfig);
- void SGenErr (void);
-
-
-
- int main (int argc, char *argv[], char *envp[]) {
- Integer result = kSuccess;
- TSParms usrCLParms;
- Integer foundVRefNum;
- LongInt foundDirID, response;
- OSErr err;
-
- InitGraf(&qd.thePort);
- InitCursorCtl(nil);
-
- /* Make parameters globally available. */
- argList = argv;
- argCount = argc;
- pShellVariable = envp;
-
- /* Try to open the Prefs file. */
- err = Gestalt(gestaltFSAttr,&response);
- gHasFSSpecCalls = err == noErr && (response & 1 << gestaltHasFSSpecCalls) != 0;
- if (gHasFSSpecCalls) {
- /* use cool new System 7.0 stuff */
- FindFolder(kOnSystemDisk,kPreferencesFolderType,kCreateFolder,&foundVRefNum,&foundDirID);
- FSMakeFSSpec(foundVRefNum,foundDirID,sPrefsFileNameP,gPrefsFileSpec);
- gDSRPrefs = FSpOpenResFile(gPrefsFileSpec,fsRdWrPerm);
- }
- else {
- /* use a gross full pathname built from an MPW Shell variable */
- strcpy(gPrefsFile,getenv("SystemFolder"));
- strcat(gPrefsFile,sPrefsFileNameC);
- gDSRPrefs = openresfile(gPrefsFile);
- }
-
- /* Set default parameters and parse the command line for differences. */
- usrCLParms.sLineType = S1;
- usrCLParms.fileName = nil;
- usrCLParms.resourceType = '\0\0\0\0';
- usrCLParms.resourceID = 0;
- usrCLParms.sLineBytes = 32;
- usrCLParms.loadAddress = 0;
- usrCLParms.execAddress = 0;
- usrCLParms.reqHeader = true;
- usrCLParms.newHeader = false;
- result = ParseCLParms(&usrCLParms);
-
- if (result == kSuccess)
- if (usrCLParms.resourceType == '\0\0\0\0')
- result = SDumpData(&usrCLParms);
- else
- result = SDumpResource(&usrCLParms);
-
- if (result > kSuccess)
- fprintf(stderr,"### %s: Errors prevented normal completion.\n",argList[0]);
-
- /* Close the Prefs file if it's open. */
- if (gDSRPrefs != -1)
- CloseResFile(gDSRPrefs);
-
- return result;
-
- }
-
-
-
- Integer ParseCLParms (TSParms *usrCLParms) {
- LongInt i, j, files = 0;
- char *thisArg;
- Integer argLen;
- Boolean hasOperand;
- Integer result = kSuccess;
-
- for (i = 1; i < argCount; i++) {
- if (*argList[i] != '-') {
- /* this argument is a filename */
- argList[++files] = argList[i]; /* collect filenames together */
- }
- else {
- /* this argument is an option */
- argLen = strlen(thisArg = argList[i]);
- for (j = 1; j < argLen; j++)
- thisArg[j] = tolower(thisArg[j]); /* convert string to lower case */
-
- /* Implement various changes to default settings. */
- if (!strcmp(thisArg,"-s1"))
- usrCLParms->sLineType = S1;
- else if (!strcmp(thisArg,"-s2"))
- usrCLParms->sLineType = S2;
- else if (!strcmp(thisArg,"-s3"))
- usrCLParms->sLineType = S3;
- else if (!strcmp(thisArg,"-h"))
- usrCLParms->reqHeader = false;
- else if (!strcmp(thisArg,"-nh"))
- usrCLParms->newHeader = true;
- else if ((hasOperand = i < argCount - 1) && !strcmp(thisArg,"-rt")) {
- usrCLParms->resourceType = *(ResType *)strtok(argList[++i],"=");
- usrCLParms->resourceID = (Integer)atoi(strtok(NULL,""));
- }
- else if (hasOperand && !strcmp(thisArg,"-a"))
- usrCLParms->loadAddress = (Ptr)strtol(argList[++i],(char **)NULL,16);
- else if (hasOperand && !strcmp(thisArg,"-x"))
- usrCLParms->execAddress = (Ptr)strtol(argList[++i],(char **)NULL,16);
- else if (hasOperand && !strcmp(thisArg,"-b"))
- usrCLParms->sLineBytes = (Integer)atoi(argList[++i]);
- else {
- /* bad parameter */
- BadParmErr();
- if (strstr("-a-b-rt-x",thisArg) == NULL)
- fprintf(stderr,"Invalid option %s.\n",thisArg);
- else
- fprintf(stderr,"Option %s requires an operand.\n",thisArg);
- result = kSyntaxErr;
- }
- }
- }
-
- /* Validate a single file and return its path name. */
- if (files == 1)
- usrCLParms->fileName = argList[1];
- else {
- result = kSyntaxErr;
- if (files == 0) {
- BadParmErr();
- fprintf(stderr,"No input file.\n",thisArg);
- }
- else {
- for (i = 2; i <= files; i++) {
- BadParmErr();
- fprintf(stderr,"Extra file name: %s.\n",argList[i]);
- }
- }
- }
- return result;
-
- }
-
-
-
- Integer SDumpHeader (TPSParms sConfig) {
- Handle hRsrc;
- TPSHdrData pHdr;
- Integer result = kSuccess;
- Str255 theS0Line;
-
- hRsrc = Get1Resource('SHDR',0);
- if (hRsrc == nil) {
- SGenErr();
- fprintf(stderr,"Error loading default header resource 'SHDR' (ID=0) from %s.\n",argList[0]);
- result = kProcErr;
- }
- else {
- if (sConfig->newHeader)
- ChangeHeader(hRsrc);
- MoveHHi(hRsrc);
- HLock(hRsrc);
- pHdr = *(THSHdrData)hRsrc;
- MakeSLine(S0,(Ptr)pHdr->headerAddress,pHdr->headerByte,pHdr->byteCount,theS0Line);
- fprintf(stdout,"%s\n",theS0Line);
- HUnlock(hRsrc);
- }
- return result;
- }
-
-
-
- Integer SDumpResource (TPSParms sConfig) {
- Handle hRsrc;
- ResType rType;
- char *rFile;
- LongInt dataSize;
- Integer id, fileRefNum;
- Integer result = kSuccess;
-
- fileRefNum = openrfperm(rFile = sConfig->fileName,0,fsRdPerm);
- if (fileRefNum == -1)
- result = kProcErr; /* will print diagnostics later */
- else {
- hRsrc = Get1Resource(rType = sConfig->resourceType,id = sConfig->resourceID);
- if (hRsrc == nil) {
- CloseResFile(fileRefNum);
- result = kProcErr; /* will print diagnostics later */
- }
- else {
- dataSize = SizeResource(hRsrc);
- DetachResource(hRsrc);
- CloseResFile(fileRefNum);
- MoveHHi(hRsrc);
- HLock(hRsrc);
-
- if (sConfig->reqHeader)
- result = SDumpHeader(sConfig);
-
- if (result == kSuccess)
- result = SDumpBuffer(*hRsrc,dataSize,sConfig,true);
-
- HUnlock(hRsrc);
- DisposHandle(hRsrc);
- }
- }
-
- if (result != kSuccess) {
- if (fileRefNum == -1) {
- SGenErr();
- fprintf(stderr,"Could not open resource file %s.\n",rFile);
- }
- else if (hRsrc == nil) {
- SGenErr();
- fprintf(stderr,"Could not load resource '%.4s' (ID=%d).\n",&rType,id);
- }
- }
- return result;
-
- }
-
-
-
- Integer SDumpData (TPSParms sConfig) {
- Handle dataBuf;
- char *dFile;
- Integer fileRefNum, fErr = noErr, dumpErr = kSuccess;
- LongInt byteCount, totalBytes = 0;
- Boolean eof;
- Integer result = kSuccess;
-
- dataBuf = NewHandle(kBlockSize);
- if (dataBuf == nil) {
- SGenErr();
- fprintf(stderr,"Memory allocation failure.\n");
- result = kSysErr;
- }
- else {
- MoveHHi(dataBuf);
- HLock(dataBuf);
- fErr = fsopen(dFile = sConfig->fileName,0,&fileRefNum);
- if (fErr != noErr) {
- SGenErr();
- fprintf(stderr,"Could not open data file %s.\n",dFile);
- result = kProcErr;
- }
- else {
- byteCount = 1;
- if (fErr = FSRead(fileRefNum,&byteCount,*dataBuf) != eofErr) {
- /* Make sure there's some data before outputting the header. */
- SetFPos(fileRefNum,fsFromStart,0);
- if (sConfig->reqHeader)
- result = SDumpHeader(sConfig);
- }
-
- if (result == kSuccess)
- do {
- byteCount = kBlockSize;
- fErr = FSRead(fileRefNum,&byteCount,*dataBuf);
- eof = fErr == eofErr;
- if (fErr == noErr || eof) {
- dumpErr = SDumpBuffer(*dataBuf,byteCount,sConfig,eof && totalBytes > 0);
- sConfig->loadAddress += byteCount;
- totalBytes += byteCount;
- }
- } while (dumpErr == kSuccess && fErr == noErr);
-
- /* handle error conditions which may have resulted */
- if (dumpErr != kSuccess)
- result = dumpErr; /* diagnostics printed in SDumpBuffer */
- else {
- if (fErr != eofErr) {
- SGenErr();
- fprintf(stderr,"Error reading data file %s.\n",dFile);
- result = kProcErr;
- }
- else
- if (totalBytes == 0) {
- SGenErr();
- fprintf(stderr,"Input file %s has an empty data fork.\n",dFile);
- result = kProcErr;
- }
- }
- FSClose(fileRefNum);
- }
- DisposHandle(dataBuf);
- }
- return result;
-
- }
-
-
-
- /* SDumpBuffer may cause memory to move, as it allocates a handle! */
- Integer SDumpBuffer (Ptr pData, LongInt count, TPSParms sConfig, Boolean termRec) {
- Handle lineBuffer;
- Ptr thisLoadAddress;
- Integer addrBytes, reqLineBytes, maxBytes, thisLineBytes;
- TSLine sType;
-
- sType = sConfig->sLineType;
- addrBytes = AddressSize(sType);
-
- /* Allocate a buffer for building S-Lines. */
- reqLineBytes = sConfig->sLineBytes;
- if (reqLineBytes > (maxBytes = 254 - addrBytes)) {
- SGenErr();
- fprintf(stderr,"S%d record maximum data bytes = %d.\n",sType,maxBytes);
- return kProcErr;
- }
- lineBuffer = NewHandle(7 + 2 * (addrBytes + reqLineBytes));
- if (lineBuffer == nil) {
- SGenErr();
- fprintf(stderr,"Memory allocation failure.\n");
- return kSysErr;
- }
- MoveHHi(lineBuffer);
- HLock(lineBuffer); /* Writing to standard output may move memory as well! */
-
- thisLoadAddress = sConfig->loadAddress;
- /* Build S-Lines for all the data in turn. */
- while (count > 0) {
- thisLineBytes = (count < reqLineBytes) ? count : reqLineBytes;
- MakeSLine(sType,thisLoadAddress,pData,thisLineBytes,*lineBuffer);
- fprintf(stdout,"%s\n",*lineBuffer);
- pData += thisLineBytes;
- count -= thisLineBytes;
- thisLoadAddress += thisLineBytes;
- }
-
- /* Build a termination record appropriate to type of S-Record block. */
- if (termRec) {
- MakeSLine(10 - sType,sConfig->execAddress,nil,0,*lineBuffer);
- fprintf(stdout,"%s\n",*lineBuffer);
- }
-
- DisposHandle(lineBuffer);
- return kSuccess;
-
- }
-
-
-
- void MakeSLine (TSLine sType, Ptr loadAddr, Ptr pData, Integer dataBytes, StringPtr sLine) {
- Integer i, offset, addrBytes;
- LongInt checksum;
-
- SpinCursor(1);
- addrBytes = AddressSize(sType);
-
- /* Begin the S-Line with 'S' after first storing sType in the second byte. */
- JamAsciiHexByte( (Byte)sType,sLine,0);
- sLine[0] = 'S';
-
- /* Initialize checksum with record length and add record length to the S-Line. */
- checksum = addrBytes + dataBytes + 1;
- JamAsciiHexByte( (Byte)checksum,sLine,2);
-
- /* Checksum and store the load address. */
- for (i = 0, offset = 2 + 2 * addrBytes; i < addrBytes; i++, offset -= 2) {
- checksum += (Byte)loadAddr;
- JamAsciiHexByte( (Byte)loadAddr,sLine,offset);
- (LongInt)loadAddr >>= 8;
- }
-
- /* Checksum and store the data bytes. */
- for (i = 0, offset = 4 + 2 * addrBytes; i < dataBytes; i++, offset += 2) {
- checksum += *pData;
- JamAsciiHexByte(*pData,sLine,offset);
- pData++;
- }
-
- /* Invert all the checksum bits and store the low byte for transmission. */
- checksum = ~checksum;
- JamAsciiHexByte( (Byte)checksum,sLine,4 + 2 * (addrBytes + dataBytes) );
-
- /* Housekeeping--Terminate with NULL. */
- sLine[6 + 2 * (addrBytes + dataBytes)] = '\0';
-
- }
-
-
-
- void JamAsciiHexByte (Byte oneByte, StringPtr pStr, Integer offset) {
- static unsigned char hexDigit[] = "0123456789ABCDEF";
-
- /* Convert a byte to its ASCII hexadecimal representation. */
- /* Jam it into a string (*strBuffer) at offset strPos. */
- pStr[offset] = hexDigit[oneByte >> 4];
- pStr[offset+1] = hexDigit[oneByte & 0x0F];
-
- }
-
-
-
- Integer AddressSize (TSLine sType) {
- Integer addrBytes;
-
- /* Address field size depends on sType. */
- switch (sType) {
- case S0: case S1: case S9:
- addrBytes = 2;
- break;
- case S2: case S8:
- addrBytes = 3;
- break;
- case S3: case S7:
- addrBytes = 4;
- break;
- }
- return addrBytes;
-
- }
-
-
-
- void BadParmErr (void) {
-
- fprintf(stderr,"### %s: Syntax: ",argList[0]);
- fprintf(stderr,"DumpSRec [-a addr] [-b count] [-h | -nh] [-rt type[=id]] ");
- fprintf(stderr,"[-s1 | -s2 | -s3] [-x addr] fileName [> dump] [≥ progress]\n");
- fprintf(stderr,"### %s: Bad parameter: ",argList[0]);
-
- }
-
-
-
- void SGenErr (void) {
-
- fprintf(stderr,"### %s: Error in S-Record generation: ",argList[0]);
-
- }
-
-
-
- void ChangeHeader (Handle hRsrc) {
- DialogPtr pAskHdr;
- Integer itemHit;
- Integer itemType;
- Handle item;
- Rect box;
- Str255 header;
- Handle newRsrc;
-
- pAskHdr = GetNewDialog(rHdrDLOG,nil,(WindowPtr)-1);
- CenterWindow((WindowPtr)pAskHdr,&qd.screenBits.bounds,true);
- ShowWindow((WindowPtr)pAskHdr);
- Show_Cursor(ARROW_CURSOR);
- do {
- ModalDialog(NoDefaultButton,&itemHit);
- } while (itemHit != ok && itemHit != cancel);
- GetDItem(pAskHdr,kHdrText,&itemType,&item,&box);
- GetIText(item,&header);
- DisposDialog(pAskHdr);
- if (itemHit == ok) {
- (**(THSHdrData)hRsrc).headerAddress = 0;
- p2cstr(header);
- (**(THSHdrData)hRsrc).byteCount = strlen(header);
- strncpy((**(THSHdrData)hRsrc).headerByte,header,kMaxHdrBytes - 1);
-
- if (gDSRPrefs == -1) {
- if (gHasFSSpecCalls)
- FSpCreateResFile(gPrefsFileSpec,'','',nil);
- else
- createresfile(gPrefsFile);
- if (ResError() != noErr)
- fprintf(stderr,"### %s: Error creating preferences file.\n",argList[0]);
- else {
- if (gHasFSSpecCalls)
- gDSRPrefs = FSpOpenResFile(gPrefsFileSpec,fsRdWrPerm);
- else
- gDSRPrefs = openresfile(gPrefsFile);
- newRsrc = hRsrc;
- HandToHand(&newRsrc);
- addresource(newRsrc,'SHDR',0,"");
- WriteResource(newRsrc);
- DisposHandle(newRsrc);
- }
- }
- else {
- ChangedResource(hRsrc);
- if (ResError() != noErr)
- fprintf(stderr,"### %s: Cannot modify default header.\n",argList[0]);
- }
- }
-
- }
-
-
-
- void CenterWindow (WindowPtr theWindow, Rect *theRect, Boolean isDialog)
- {
- Point offscreenPt, portRef;
- Rect portRect, strucRect, ctrRect = *theRect;
- short portH, portV, windH, windV;
- short grayDiv, x, y;
- Boolean originalState;
-
- SetPort(theWindow);
- originalState = ((WindowPeek) theWindow)->visible;
-
- // According to the Human Interface Notes, dialogs are nominally
- // centered evenly left and right, with gray space divided 20%
- // above and 80% below (1/5 above and 4/5 below) the window.
-
- if (isDialog)
- grayDiv = kDlogGrayDiv;
- else
- grayDiv = kEqualGrayDiv; // or we can actually center it
-
- // The window is temporarily moved beyond the lower right corner of
- // the desktop region. The dimensions of the window's portRect form
- // a basis for additional margin to guarantee that no part of the
- // window's frame will appear (even momentarily) in the lower right
- // corner of the desktop.
-
- offscreenPt = botRight((**GetGrayRgn()).rgnBBox);
- portRect = theWindow->portRect;
- offscreenPt.h += rectWidth(portRect);
- offscreenPt.v += rectHeight(portRect);
- MoveWindow(theWindow, offscreenPt.h, offscreenPt.v, false); // move it offscreen
- ShowHide(theWindow, true);
-
- // can only get structure data after window is "drawn"
-
- strucRect = (**((WindowPeek) theWindow)->strucRgn).rgnBBox;
- ShowHide(theWindow, originalState); // leave it the way it was
- if (EqualRect(theRect, &qd.screenBits.bounds))
- ctrRect.top += GetMBarHeight();
- portH = rectWidth(ctrRect);
- portV = rectHeight(ctrRect);
- windH = rectWidth(strucRect);
- windV = rectHeight(strucRect);
- portRef = topLeft(portRect);
- LocalToGlobal(&portRef);
-
- // Note that while the intent is to center the window structure,
- // MoveWindow sets the location of the window content, so it is
- // necessary to add the top and left frame thicknesses to the
- // arguments of MoveWindow.
-
- x = ctrRect.left + (portH - windH) / kEqualGrayDiv + (portRef.h - strucRect.left);
- y = ctrRect.top + (portV - windV) / grayDiv + (portRef.v - strucRect.top);
- MoveWindow(theWindow, x, y, false); // finally it's centered!
- }
-
-
-
- pascal Boolean NoDefaultButton (DialogPtr theDialog, EventRecord *theEvent, Integer *itemHit) {
- Boolean cmdKeyPressed, result = false;
- Integer charCode;
- Integer itemType;
- Handle item;
- Rect box;
- LongInt finalTicks;
-
- /* This is a filter proc for a modal dialog which needs to use the return key for */
- /* something other than a default button, for instance a dialog with a relatively */
- /* large TextEdit field. For those that like using the keyboard to dismiss dialogs, */
- /* it supports Cmd-Return and Enter as equivalents to the OK button and Escape as */
- /* an equivalent to the Cancel button. */
- if (theEvent->what == keyDown) {
- charCode = theEvent->message & 0xFF;
- cmdKeyPressed = (theEvent->modifiers & cmdKey) != 0;
- if (charCode == chEnter || charCode == chReturn && cmdKeyPressed) {
- result = true;
- *itemHit = ok;
- }
- else if (charCode == chEscape) {
- result = true;
- *itemHit = cancel;
- }
- if (result) {
- GetDItem(theDialog,*itemHit,&itemType,&item,&box);
- HiliteControl((ControlHandle)item,inButton);
- Delay(8,&finalTicks);
- HiliteControl((ControlHandle)item,0);
- }
- }
-
- return result;
-
- }
-